/*
*    Phantom v2.0 GUI Automation Software
*    Copyright (C) 2009  John C. Van Arsdall (john@phantomtest.com)
*
*    This program is free software; you can redistribute it and/or modify
*    it under the terms of the GNU General Public License as published by
*    the Free Software Foundation; either version 2 of the License, or
*    (at your option) any later version.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU General Public License for more details.
*
*    You should have received a copy of the GNU General Public License along
*    with this program; if not, write to the Free Software Foundation, Inc.,
*    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include "StdAfx.h"
#include "connection.h"
#include "PhantomAgent.h"
#include "PhantomAgentDlg.h"
#include "SSI_ConsoleClient.h"
#include "SSI_ScriptClient.h"
#include "SSI_LibraryManager.h"
#include "LibMgrSingleton.h"
#include ".\connection.h"

int CConnection::STATE_STOPPED = 1;
int CConnection::STATE_RUNNING = 2;

/*
typedef int (*FUNCPROC)(CEngine*); 
int LoadDLL(const char* Name, CEngine* theEngine){

	HMODULE hLib = 0;
	FUNCPROC Func;
	string aStr = Name;
	hLib = LoadLibrary(aStr.c_str());
	if(!hLib){
		return 0;
	}
	Func = (FUNCPROC)GetProcAddress(hLib, "RegisterFunctions");
	if(!Func){
		FreeLibrary(hLib);
		return 0;
	}
	(Func)(theEngine);
	return 1;
}
*/

/*
int LoadDLLs(CEngine* theEngine, const char* ExternalFile){
	File aFile;
	String aStr;

	if(!aFile.Open(ExternalFile, "r")){
		//printf("Warning: %s (external DLL list) not found\n", ExternalFile);
		return 0;
	}

	while(aFile.ReadLine(aStr) >= 0){
		theEngine->SetPackageName(aStr.Str());
		LoadDLL(aStr.Str(), theEngine);
	}
	return 1;
}
*/



CConnection::CConnection(SSI_BOOL isReged)
: iPort(0)
, pW(NULL)
, m_Socket(NULL)
, m_RunState(0)
, m_ListID(0)
, m_SentCtr(0)
, m_RecvCtr(0)
{
		m_ConnectionStatus = "Not Connected";
    m_ConnectionInfo = "Unknown";
    bRegistered = isReged;
}

CConnection::~CConnection(void)
{
	if(m_Socket){
		delete m_Socket;
		m_Socket = 0;
	}
}

int CConnection::Run(void)
{
	if(m_Socket == 0){
    m_ConnectionStatus = "ERROR ID 001";
		return 0;
	}

	if(pW == 0){
    m_ConnectionStatus = "ERROR ID 002";
		return 0;
	}

  m_ConnectionStatus = "Connecting";

  m_RunState = STATE_RUNNING;
	m_stream.SetSocket(m_Socket);

	SSI_INT64 RunType = 0;
	String ScriptPath;
	String ScriptArgs;
	SSI_INT64 RunMode = NORMAL_MODE;
	m_stream.Initialize(RunType, RunMode, ScriptPath, ScriptArgs);

/*
	// Get type of run (script or console)
	CSockCmd aCmd;
	SSI_INT64 RunType = 0;
	String ScriptPath;
	SSI_INT64 Flags = 0;
	SSI_INT64 RunMode = NORMAL_MODE;

	SSI_VERBOSE_LOG("Connection: Sending Action");
	aCmd.Set(SSI_ACTION_REQUEST, 0, 0);
	if(!aCmd.SendMe(*m_Socket)){
		m_stream.CloseConnection();
		m_stream.CleanUp();
		m_RunState = STATE_STOPPED;
    m_ConnectionStatus = "ERROR ID 003";
		return 0;
	}
	m_SentCtr++;


  // TRY USING SELECT FUNCTION TO DETERMINE IF DATA IS AVAILABLE!  ELSE, CAN BECOME BLOCKED

  SSI_VERBOSE_LOG("Connection: Reading Action");
	if(!aCmd.ReadMe(*m_Socket)){
		SSI_VERBOSE_LOG("Could not read action response.\n");
		m_stream.CloseConnection();
		m_stream.CleanUp();
		m_RunState = STATE_STOPPED;
    m_ConnectionStatus = "ERROR ID 004";
		return 0;
	}
	m_RecvCtr++;
	SSI_VERBOSE_LOG("Connection: Checking Response");

	if(aCmd.ID != SSI_ACTION_RESPONSE){
		m_stream.CloseConnection();
		m_stream.CleanUp();
		m_RunState = STATE_STOPPED;
    m_ConnectionStatus = "ERROR ID 005";
		return 0;
	}

	SSI_VERBOSE_LOG("Connection: Checking Mode");
	if(aCmd.Size == 0){
		RunType = 0;    // Console mode
	}else{
		RunType = 1;    // Script mode
		ScriptPath = (const char*)(aCmd.Data);
		if(ScriptPath.GetLength() != aCmd.Size){
			String sErr = "Invalid file name";
			aCmd.Set(RSP_NACK, sErr.GetLength(), sErr.Str());
			aCmd.SendMe(*m_Socket);
			m_SentCtr++;
			m_stream.CloseConnection();
			m_stream.CleanUp();
			m_RunState = STATE_STOPPED;
      m_ConnectionStatus = "ERROR ID 006";
			return 0;
		}
	}

	SSI_VERBOSE_LOG("Connection: ACK 1");
	aCmd.Set(RSP_ACK, 0, 0);
	if(!aCmd.SendMe(*m_Socket)){
		m_stream.CloseConnection();
		m_stream.CleanUp();
		m_RunState = STATE_STOPPED;
    m_ConnectionStatus = "ERROR ID 007";
		return 0;
	}
	m_SentCtr++;

	SSI_VERBOSE_LOG("Connection: Flag Request");
	// Read Flags
	aCmd.Set(SSI_FLAG_REQUEST, 0, 0);
	if(!aCmd.SendMe(*m_Socket)){
		m_stream.CloseConnection();
		m_stream.CleanUp();
		m_RunState = STATE_STOPPED;
    m_ConnectionStatus = "ERROR ID 008";
		return 0;
	}
	m_SentCtr++;

	if(!aCmd.ReadMe(*m_Socket)){
		m_stream.CloseConnection();
		m_stream.CleanUp();
		m_RunState = STATE_STOPPED;
    m_ConnectionStatus = "ERROR ID 008";
		return 0;
	}
	m_RecvCtr++;

	SSI_VERBOSE_LOG("Connection: Checking Flag Response");
	if(aCmd.ID != SSI_FLAG_RESPONSE){
		m_stream.CloseConnection();
		m_stream.CleanUp();
		m_RunState = STATE_STOPPED;
    m_ConnectionStatus = "ERROR ID 009";
		return 0;
	}

	if(aCmd.Size != 4){
		String sErr = "Invalid flag packet";
		aCmd.Set(RSP_NACK, sErr.GetLength(), sErr.Str());
		aCmd.SendMe(*m_Socket);
		m_SentCtr++;
		m_stream.CloseConnection();
		m_stream.CleanUp();
		m_RunState = STATE_STOPPED;
    m_ConnectionStatus = "ERROR ID 010";
		return 0;
	}
	Flags = *(int*)(aCmd.Data);
	if(Flags & DEBUG_BIT){
		RunMode = DEBUG_MODE;
	}

	SSI_VERBOSE_LOG("Connection: ACK 2");
	aCmd.Set(RSP_ACK, 0, 0);
	if(!aCmd.SendMe(*m_Socket)){
		m_stream.CloseConnection();
		m_stream.CleanUp();
		m_RunState = STATE_STOPPED;
    m_ConnectionStatus = "ERROR ID 011";
		return 0;
	}
	m_SentCtr++;

  String sArgs;
  if(Flags & ARGS_BIT){
		// Read Flags
		aCmd.Set(SSI_ARGS_REQUEST, 0, 0);
		if(!aCmd.SendMe(*m_Socket)){
			//printf("Could not send arg request.\n");
			m_stream.CloseConnection();
			m_stream.CleanUp();
  		m_RunState = STATE_STOPPED;
      m_ConnectionStatus = "ERROR ID 012";
			
      return 0;
		}
    m_SentCtr++;

		if(!aCmd.ReadMe(*m_Socket)){
			//printf("Could not read arg response.\n");
			m_stream.CloseConnection();
			m_stream.CleanUp();
	   	m_RunState = STATE_STOPPED;
      m_ConnectionStatus = "ERROR ID 013";
			
			return 0;
		}
    m_RecvCtr++;

		if(aCmd.ID != SSI_ARGS_RESPONSE){
			//printf("Invalid argument response.\n");
			m_stream.CloseConnection();
			m_stream.CleanUp();
  		m_RunState = STATE_STOPPED;
      m_ConnectionStatus = "ERROR ID 014";
			
			return 0;
		}

    sArgs = aCmd.Data;

	  SSI_VERBOSE_LOG("Arguments: ACK");
	  aCmd.Set(RSP_ACK, 0, 0);
	  if(!aCmd.SendMe(*m_Socket)){
		  m_stream.CloseConnection();
		  m_stream.CleanUp();
		  m_RunState = STATE_STOPPED;
      m_ConnectionStatus = "ERROR ID 011";
		  return 0;
	  }
	  m_SentCtr++;

  }
*/

  m_ConnectionStatus = "Connected";

	SSI_VERBOSE_LOG("Connection: Status Connected");


	// Console op, so do console
	if(RunType == 0){
		// This goes into a thread
    m_ConnectionInfo = "Console Session";
		CConsoleClient aClient(&m_stream, &m_stream);
    if(bRegistered){
		  GetLibManager().LoadDLLs(aClient.Engine, "Externals.dat");
    }else{
      m_stream.WarningDisp("[AGENT] Running in un-registered mode.  External functions not loaded.", 1);
    }
		m_stream.SetEngine(aClient.Engine);
		aClient.Loop();
		GetLibManager().FreeDLLs(aClient.Engine);
		m_stream.CloseConnection();
		m_stream.CleanUp();
	}else{
		// This goes into a thread
    m_ConnectionInfo = String("Script: ") + ScriptPath;

		SSI_VERBOSE_LOG("Connection: Script Begin");
		CScriptClient aClient(&m_stream, &m_stream);

		SSI_VERBOSE_LOG("Connection: Setting Engine");
		m_stream.SetEngine(aClient.Engine);
		
		SSI_VERBOSE_LOG("Connection: Loading DLLs");

    if(bRegistered){
		  GetLibManager().LoadDLLs(aClient.Engine, "Externals.dat");
    }else{
      m_stream.WarningDisp("[AGENT] Running in un-registered mode.  External functions not loaded.", 1);
    }
		
		//if(nPrompt){              // need to find a way to add this
		//	aClient.bPrompt = true;
		//}else{
		//	aClient.bPrompt = false;
		//}
		
		SSI_VERBOSE_LOG("Connection: Load Script");
    SSI_VERBOSE_LOG(ScriptPath.Str());
		if(aClient.Load(ScriptPath)){
		}else{
			SSI_VERBOSE_LOG("Connection: LOAD ERROR");
			m_ConnectionStatus = "Stopped";
			m_RunState = STATE_STOPPED;
			SSI_VERBOSE_LOG("Connection: Clean Up");
			GetLibManager().FreeDLLs(aClient.Engine);
			m_stream.CloseConnection();
			m_stream.CleanUp();
      m_ConnectionStatus = "ERROR ID 012";
			return 0;
			// send an error
		}

    SSI_VERBOSE_LOG("Connection: Eval Args");
    if(ScriptArgs.GetLength() > 0){
      if(!aClient.EvaluateArguments(ScriptArgs)){
        SSI_VERBOSE_LOG("Connection: Clean Up - Bad Args");
		    GetLibManager().FreeDLLs(aClient.Engine);
        m_ConnectionStatus = "Argument Error";
        m_RunState = STATE_STOPPED;
		    m_stream.CloseConnection();
		    m_stream.CleanUp();
        return 0;
      }
    }

		SSI_VERBOSE_LOG("Connection: Run Script");
		aClient.Run(RunMode);
		SSI_VERBOSE_LOG("Connection: Clean Up");
		GetLibManager().FreeDLLs(aClient.Engine);
		m_stream.CloseConnection();
		m_stream.CleanUp();
	}

	m_ConnectionStatus = "Stopped";
	m_RunState = STATE_STOPPED;

	return 0;
}

void CConnection::SetSocket(CSocketSSI* inSocket)
{
	m_Socket = inSocket;
}

void CConnection::SetParent(CPhantomAgentDlg* inPW)
{
	pW = inPW;
}

int CConnection::getSentCtr(void)
{
	return m_SentCtr + m_stream.getSentCtr();
}

int CConnection::getRecvCtr(void)
{
	return m_RecvCtr + m_stream.getRecvCtr();
}
